home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
DDJ0992.ARJ
/
DUNHAM.LS7
< prev
next >
Wrap
Text File
|
1992-04-20
|
50KB
|
1,409 lines
/* Listing #7: sparc.c signal handling & stack traceback */
#include <stdio.h>
#include <signal.h> /* for signal definitions */
#include <a.out.h> /* for NSYMOFF etc */
#include <stab.h> /* for N_SLINE etc */
#include <string.h> /* for strtok */
#include <floatingpoint.h> /* for fpe handling */
/*----------------- local defines --------------------*/
#undef PROTOTYPES /* ignore prototype info */
#undef DEBUGPRINT /* we don't want debug info */
#define STACKDUMP 0 /* set to 1 to get 32bit stack dumps */
#define FRAMEDUMP 0 /* set to 1 to dump each stack frame */
#define PARAMDUMP 0 /* set to 1 to get parameter dumps */
#define SYMBOLDUMP 0 /* set to 1 to get local symbol dumps */
#define JUMPPC 15 /* how to find next program counter */
#define JUMPSP 14 /* how to find next stack pointer */
#define MAXLEVEL 40 /* maximum number of nested subroutine calls */
#define MAXPARAM 40 /* maximum number of subroutine parameters */
#define DUMPSIZE 256 /* size of stack dump in longwords */
#define NSIGNAL 31 /* #signals to describe in text array */
#define STREQ(a,b) (strcmp((a),(b))==0)
#define STRNEQ(a,b) (strcmp((a),(b))!=0)
#define CNULL '\0'
#ifdef PROTOTYPES
# define P_(s) s
#else
# define P_(s) ()
#endif
#ifdef DEBUGPRINT
# define DBPRINT(s) printf s
#else
# define DBPRINT(s)
#endif
/* defines for data dictionary: basic types */
#define D_INT 1
#define D_CHAR 2
#define D_LONG 3
#define D_SHORT 4
#define D_UCHAR 5
#define D_USHORT 6
#define D_ULONG 7
#define D_UINT 8
#define D_FLOAT 9
#define D_DOUBLE 10
#define D_VOID 11
#define D_NONE 12
/*----------------- external functions --------------------*/
char *malloc();
char *getenv();
/*----------------- internal functions --------------------*/
static void trb_exefind P_((int argc, char *argv));
static void trb_exeinfo();
static void trb_dictionary P_((int ilevel, FILE fp, FILE fp2));
static void trb_symboldump();
static void trb_stackdump P_((unsigned long start, int nn, FILE **fp));
static void trb_framedump P_((unsigned long sp, unsigned long pc,
unsigned long fremeend, FILE **fp));
static void trb_getline P_((int nlevel));
static void trb_params P_((int ilevel, FILE fp, FILE fp2));
static void trb_symbols P_((int ilevel, FILE fp, FILE fp2));
static void trb_traceback P_((int nlevel));
void trb_userinfo P_((FILE fp));
void trb_handle P_((int sig,int code,struct sigcontext *scp, char *addr));
static void trb_sigtextinit();
static char *trb_codetext P_((int sig, int code));
static void trb_signal();
void trb_signalinit P_((int argc, char *argv[]));
static char *strstr();
static void str_getdelimited P_((char *inttext, char *bounds,
char *outtext));
static void str_whiteout P_((char *string, char *chars));
/*----------------- structure definitions -----------------*/
struct levelstr /* info for each function in traceback */
{unsigned long stackpointer; /* start of stack frame */
unsigned long programcounter; /* return address */
unsigned long frameend; /* end of stack frame (+4) */
long fileaddr,funcaddr; /* addresses into string table */
char funcname[256]; /* name of function */
char filename[256]; /* name of source file */
int found; /* 0 if function not found */
int filesymbol; /* symbol # for start of source file */
int funcsymbol; /* symbol # for start of function */
int line; /* line number in source file */
};
struct exestr /* information about the executable file */
{int nsym; /* number of symbols in symbol table */
unsigned long magic; /* the magic number of the file */
long stroffset; /* offset to the string table */
long symoffset; /* offset to the symbol table */
char name[256]; /* path to the file */
};
struct dictstr /* a dictionary of defined variable types */
{char match[8]; /* the defined type (0,nnn) */
char basetype[8]; /* what it is defined from (0,nnn) */
int code; /* our base identifier ie D_INT */
char fullstring[80]; /* as it was read from COFF */
int ptr; /* 1 if it is a pointer */
int lower,upper; /* array bounds */
};
/*----------------- global variables ----------------------*/
char sigtext[NSIGNAL+1][64]; /* describe signal values */
struct levelstr level[MAXLEVEL]; /* one per stack frame */
struct exestr exe;
struct dictstr dictionary[200]; /* allow 200 per source file */
int ndict; /* number of types per source file */
FILE *fpcrash,*fpstackdump,*fpframedump;
/* pointers to files CRASH, STACKDUMP, FRAMEDUMP */
char description[13][16] = {"???","int","char","long","short","unsigned char",
"unsigned short","unsigned long","unsigned int","float",
"double","void","???" };
/****************************************************************/
/* trb_exefind */
/* find the path of the file we are executing */
/****************************************************************/
static void trb_exefind(argc,argv)
int argc;
char *argv[];
{
FILE *fp;
int ll;
char name[256],*path;
char *ptr,trial[256];
/*---------------------------------*/
/* get name of program */
strcpy(name,argv[0]);
/* 1: if name contains a slash, assume it is the direct path */
ptr= strchr(name,'/');
if(ptr!=NULL)
{strcpy(trial,name);
fp= fopen(trial,"r");
if(fp!=NULL)
{fclose(fp);strcpy(exe.name,trial);return;}
}
/* 2: look in the user's path */
ptr= getenv("PATH");
ll= strlen(ptr);
path= malloc(ll+1);
strcpy(path,ptr);
/* separate path string into its components */
ptr= strtok(path,":");
while(ptr!=NULL)
{strcpy(trial,ptr);
strcat(trial,"/");
strcat(trial,name);
DBPRINT(("trial exe is %s \n",trial));
fp= fopen(trial,"r");
if(fp!=NULL) {fclose(fp);strcpy(exe.name,trial);free(path);return;}
ptr= strtok(NULL,":");
}
/* 3: try the local directory in case it is not in the path */
strcpy(trial,"./");
strcat(trial,name);
DBPRINT(("trial exe is %s \n",trial));
fp= fopen(trial,"r");
if(fp!=NULL){fclose(fp);strcpy(exe.name,trial);return;}
} /* end of trb_exefind */
/****************************************************************/
/* trb_exeinfo */
/* get needed info from executable file header */
/****************************************************************/
static void trb_exeinfo()
{
int status;
unsigned long magic;
FILE *fp;
struct exec header; /* exe file header (from a.out.h) */
struct nlist symbol; /* symbol table entry */
/*--------------------*/
/* open exe file */
fp= fopen(exe.name,"r");
if(fp==NULL)
{printf("can't open %s\n",exe.name);
exit(1);}
/* read the file header */
status= fread(&header,sizeof(header),1,fp);
if(status==0) {printf("could not read header\n"); exit(2);}
/* is the magic number okay ? */
magic= header.a_magic;
status= N_BADMAG(header);
if(status!=0)
{printf("bad magic number = %ld 0x%lx 0%lo \n",magic,magic,magic);
exit(3);
}
exe.magic= magic;
/* how big is the symbol table */
exe.nsym= header.a_syms/sizeof(symbol);
if(exe.nsym==0) exit(4);
/* get file offsets for symbol table & string table */
exe.symoffset= N_SYMOFF(header);
exe.stroffset= N_STROFF(header);
fclose(fp);
} /* end of trb_exeinfo */
/****************************************************************/
/* trb_dictionary */
/* make a "data dictionary" for a source file */
/****************************************************************/
static void trb_dictionary(ilevel,fp,fp2)
int ilevel;
FILE *fp, *fp2;
{
int i,j,status,type,off;
int low,high,code,pointer;
int isym;
struct nlist symbol; /* symbol table entry */
long nseek;
char *ptr, *ptr2;
char ttext[1024],tempstring[64];
char symbolname[32],junk1[8],junk2[8],match[8];
/*--------------------*/
dictionary[0].code=D_INT;
dictionary[1].code=D_CHAR;
dictionary[2].code=D_LONG;
dictionary[3].code=D_SHORT;
dictionary[4].code=D_UCHAR;
dictionary[5].code=D_USHORT;
dictionary[6].code=D_ULONG;
dictionary[7].code=D_UINT;
dictionary[8].code=D_FLOAT;
dictionary[9].code=D_DOUBLE;
dictionary[10].code=D_VOID;
dictionary[11].code=D_NONE;
strcpy(dictionary[0].match,"0,1");
strcpy(dictionary[1].match,"0,2");
strcpy(dictionary[2].match,"0,3");
strcpy(dictionary[3].match,"0,4");
strcpy(dictionary[4].match,"0,5");
strcpy(dictionary[5].match,"0,6");
strcpy(dictionary[6].match,"0,7");
strcpy(dictionary[7].match,"0,8");
strcpy(dictionary[8].match,"0,9");
strcpy(dictionary[9].match,"0,10");
strcpy(dictionary[10].match,"0,11");
strcpy(dictionary[11].match,"0,12");
for(i=0;i<12;i++)
{dictionary[i].ptr=0;
dictionary[i].lower=0;
dictionary[i].upper=0;
dictionary[i].basetype[0]=CNULL;
}
/* open exe file */
fp= fopen(exe.name,"r");
fp2= fopen(exe.name,"r");
if(fp==NULL)
{printf("can't open %s\n",exe.name);
exit(1);}
ndict=12;
isym= level[ilevel].filesymbol+1; /* seek to source files' symbols */
nseek= exe.symoffset + isym*sizeof(symbol);
fseek(fp,nseek,0);
for(i=isym;i<exe.nsym;i++)
{status= fread(&symbol,sizeof(symbol),1,fp);
if(status==0) printf("could not read symbol\n");
type= symbol.n_type;
if(type==N_SO) return; /* we are at the next source file */
if(type!=N_LSYM && type!=N_PSYM) continue; /* local syms & params */
nseek= exe.stroffset+symbol.n_un.n_strx;
fseek(fp2,nseek,0);
ptr= fgets(ttext,sizeof(ttext),fp2); /* text describing symbol */
/* ignore structures for now */
str_getdelimited(ttext,"()",match);
if(match[0]!='0') continue;
/* is it a basic type */
ptr= strstr(ttext,":t(");
if(ptr!=NULL)continue;
/* extract the symbol name */
strcpy(tempstring,ttext);
str_whiteout(tempstring,":=;");
sscanf(tempstring,"%s",symbolname);
/* if an old type, go to next symbol */
ptr=strchr(ttext,'=');
if(ptr==NULL)continue;
/* it is a new type, clear some flags */
dictionary[ndict].ptr= 0;
dictionary[ndict].code= 0;
dictionary[ndict].lower= 0;
dictionary[ndict].upper= 0;
strcpy(dictionary[ndict].match,match);
/* is this new type a pointer */
ptr2=strstr(ptr,"=*(");
if(ptr2!=NULL)
{str_getdelimited(ptr2,"()",match);
strcpy(dictionary[ndict].basetype,match);
dictionary[ndict].ptr= 1;
for(j=0;j<ndict;j++)
{if(STREQ(match,dictionary[j].match))
{code= dictionary[j].code;
pointer= dictionary[j].ptr+1;
dictionary[ndict].code= code;
dictionary[ndict].ptr= pointer;
break;
}
}
ndict++;
continue;
}
/* is this new type an array */
ptr2=strstr(ptr,"=ar(");
if(ptr2!=NULL)
{strcpy(tempstring,ptr);
str_whiteout(tempstring,";()");
sscanf(tempstring,"%s %s %d %d %s",junk1,junk2,&low,&high,match);
strcpy(dictionary[ndict].basetype,match);
dictionary[ndict].lower= low;
dictionary[ndict].upper= high;
for(j=0;j<ndict;j++)
{if(STREQ(match,dictionary[j].match))
{code=dictionary[j].code;
dictionary[ndict].code=code;
break;
}
}
ndict++;
continue;
}
} /* end of loop over all symbols */
} /* end of trb_dictionary */
/****************************************************************/
/* trb_translate */
/* what kind of variable is a symbol */
/****************************************************************/
static void trb_translate(ttext,code,pointer,array)
char *ttext;
int *code, *pointer, *array;
{
int i,j,status,type,off;
int low,high,size;
int isym;
struct nlist symbol; /* symbol table entry */
long nseek;
char *ptr, *ptr2;
char tempstring[64];
char symbolname[32],junk1[8],junk2[8],match[8];
/*--------------------*/
/* zero the output flags */
*code= 0;
*pointer= 0;
*array= 0;
/* ignore structures for now */
str_getdelimited(ttext,"()",match);
if(match[0]!='0') return;
/* look in the data dictionary */
{for(j=0;j<ndict;j++)
{if(STREQ(match,dictionary[j].match))
{*code= dictionary[j].code;
*pointer= dictionary[j].ptr;
size= dictionary[j].upper-dictionary[j].lower+1;
if(size>1) *array=size;
return;
}
}
return;
}
} /* end of trb_translate */
/****************************************************************/
/* trb_verbalize */
/* print what kind of variable a symbol is */
/****************************************************************/
static void trb_verbalize(name,code,pointer,array)
char *name;
int code,pointer,array;
{
char ttext[80],size[16];
/*------------------------------------------------------*/
strcpy(ttext,name);
if(pointer>0)
strcat(ttext," is a pointer to type ");
else if(array>1)
strcat(ttext," is an array of type ");
else
strcat(ttext," is a variable of type ");
if(pointer==2) strcat(ttext,"*");
if(pointer==3) strcat(ttext,"*");
strcat(ttext,description[code]);
if(array>1) {sprintf(size," [%d] ",array); strcat(ttext,size); }
printf("%s\n",ttext);
} /* end of trb_verbalize */
/****************************************************************/
/* trb_symboldump */
/* dump text of local symbols */
/****************************************************************/
static void trb_symboldump()
{
int i,j,status,type,off;
FILE *fp, *fp2, *fpout;
struct nlist symbol; /* symbol table entry */
long nseek;
char *ptr, *ptr2;
char ttext[1024];
long fileaddr;
char filename[256];
/*--------------------*/
/* open exe file */
fp= fopen(exe.name,"r");
fp2= fopen(exe.name,"r");
if(fp==NULL)
{printf("can't open %s\n",exe.name);
exit(1);}
/* open file SYMBOLDUMP */
fpout= fopen("SYMBOLDUMP","w");
if(fpout==NULL)
{printf("can't open file SYMBOLDUMP for output\n");
exit(1);}
trb_userinfo(fpout);
fseek(fp,exe.symoffset,0);
for(i=0;i<exe.nsym;i++)
{status= fread(&symbol,sizeof(symbol),1,fp);
if(status==0) printf("could not read symbol\n");
type= symbol.n_type;
if(type==N_SO) /* source file name: name,,0,0,address */
{fileaddr= symbol.n_un.n_strx;
fseek(fp2,exe.stroffset,0);
fseek(fp2,fileaddr,1);
ptr= fgets(filename,sizeof(filename),fp2);
fprintf(fpout,"filename %s \n",filename);
}
if(type!=N_LSYM) continue;
off= symbol.n_value;
nseek= exe.stroffset+symbol.n_un.n_strx;
fseek(fp2,nseek,0);
ptr= fgets(ttext,sizeof(ttext),fp2);
fprintf(fpout,"frame offset=%d symbol text: >%s< \n",off,ttext);
} /* end of loop over all symbols */
fclose(fp);
fclose(fp2);
fclose(fpout);
} /* end of trb_symboldump */
/****************************************************************/
/* trb_stackdump */
/* dump the stack */
/****************************************************************/
static void trb_stackdump(start,nn,fp0)
unsigned long start;
int nn;
FILE **fp0;
{
int i,j;
FILE *fp;
/*------------------------------------------------------*/
fp= *fp0;
if(fp==0)
{fp= fopen("STACKDUMP","a"); /* open for append */
if(fp==NULL) fp= stdout; /* if failure, use standard out */
*fp0= fp; /* save it in case we have two crashes */
}
trb_userinfo(fp);
for (i=0; i<nn;i++)
{fprintf(fp,"%08x ", (long)start);
fprintf(fp,"%08x ", *(unsigned long *)(start));
for(j=0;j<4;j++,start++)
fprintf(fp,"%c", isprint(*(unsigned char *)(start))
? *(unsigned char *)(start) : ' ');
fprintf(fp,"\n");
}
fclose(fp);
} /* end of trb_stackdump */
/****************************************************************/
/* trb_framedump */
/* dump a stack frame */
/****************************************************************/
static void trb_framedump(stackpointer,programcounter,frameend,fp0)
unsigned long stackpointer,programcounter,frameend;
FILE **fp0;
{
int j;
unsigned long stackaddress,stackvalue;
FILE *fp;
/*------------------------------------------------------*/
fp= *fp0;
if(fp==0)
{fp= fopen("FRAMEDUMP","a");
if(fp==NULL) fp= stdout;
trb_userinfo(fp);
*fp0= fp;
}
fprintf(fp,"-----------------------------------\n");
fprintf(fp,"sp=%08x pc=%08x\n",stackpointer,programcounter);
j= 0;
stackaddress= stackpointer;
while(stackaddress<frameend)
{stackvalue= *( (long *)stackaddress);
fprintf(fp," %8x",stackvalue);
j++;
if(j==8) {fprintf(fp,"\n");j= 0;}
stackaddress= stackaddress+4;
}
if(j!=0)fprintf(fp,"\n");
fprintf(fp,"-----------------------------------\n");
} /* end of trb_framedump */
/****************************************************************/
/* trb_getline */
/* find file lines matching addresses */
/****************************************************************/
static void trb_getline(nlevel)
int nlevel;
{
FILE *fp,*fp2;
struct nlist symbol; /* symbol table entry */
unsigned long address,match,lastaddress;
int type,line,funcsymbol,filesymbol;
int i,j,ll,status;
long fileaddr,funcaddr,magic;
int iff;
char *ptr,ttext[256];
char funcname[256],filename[256];
/*----------------------*/
/* initialize */
address= 0; funcsymbol= 0; filesymbol=0;
lastaddress= 0xFFFF;
for(i=0;i<MAXLEVEL;i++)level[i].found= 0;
DBPRINT(("in trb_getline: nlevel=%d pc[0]=%x\n",nlevel,level[0].pc));
/* use first file pointer to read symbol table */
fp= fopen(exe.name,"r");
if(fp==NULL) {printf("can't open %s\n",exe.name);exit(1);}
/* use second file pointer to read the string table */
fp2= fopen(exe.name,"r");
/* read all symbols, look at source lines, file & function names */
fseek(fp,exe.symoffset,0);
for(i=0;i<exe.nsym;i++)
{status= fread(&symbol,sizeof(symbol),1,fp);
if(status==0) printf("could not read symbol\n");
type= symbol.n_type;
/* what type of symbol is it */
if(type==N_SLINE) /* src line: 0,,0,linenumber,address */
{line= symbol.n_desc;
address= symbol.n_value;
DBPRINT(("line=%d address=%x\n",line,address));
}
else if(type==N_FUN) /* procedure: name,,0,linenumber,address */
{funcaddr= symbol.n_un.n_strx;
address= symbol.n_value;
funcsymbol= i;
fseek(fp2,exe.stroffset,0);
fseek(fp2,funcaddr,1);
ptr= fgets(ttext,sizeof(ttext),fp2);
ptr= strtok(ttext,":");
ll= strlen(ptr);
if(ll>250){strncpy(funcname,ptr,250); funcname[250]= CNULL;}
else strcpy(funcname,ptr);
DBPRINT(("procedure %s address=%x\n",funcname,address));
}
else if(type==N_SO) /* source file name: name,,0,0,address */
{fileaddr= symbol.n_un.n_strx;
address= symbol.n_value;
filesymbol= i;
fseek(fp2,exe.stroffset,0);
fseek(fp2,fileaddr,1);
ptr= fgets(filename,sizeof(filename),fp2);
DBPRINT(("filename %s address=%x\n",filename,address));
}
/* does this address match one of ours? */
for(iff=0;iff<nlevel;iff++)
{if(level[iff].found==0)
{match= level[iff].programcounter;
if(address==match)
{DBPRINT(("exact match of %x found at line %d\n",match,line));
level[iff].found= 1;
level[iff].filesymbol= filesymbol; /* store symbol# of the file */
level[iff].funcsymbol= funcsymbol; /* symbol# of the function */
strcpy(level[iff].funcname,funcname);
strcpy(level[iff].filename,filename);
level[iff].line= line;
}
else if(address>match && lastaddress<match && lastaddress>(match-64))
{
DBPRINT(("match of %x before line %d, lastaddress=%x address=%x\n",
match,line,lastaddress,address));
level[iff].found= 1;
level[iff].filesymbol= filesymbol; /* store symbol# of the file */
level[iff].funcsymbol= funcsymbol; /* symbol# of the function */
strcpy(level[iff].funcname,funcname);
strcpy(level[iff].filename,filename);
level[iff].line= line-1;
}
}
}
lastaddress= address;
} /* end of loop over all nsym */
fclose(fp2);
fclose(fp);
} /* end of trb_getline */
/****************************************************************/
/* trb_params */
/* print one level of parameters */
/****************************************************************/
static void trb_params(ilevel,fp,fp2)
int ilevel;
FILE *fp, *fp2;
{
int i,status,type;
int isym,code,pointer,array;
int size,middle,sum;
long addr,off,address,newaddress,stackbase,nseek,contents;
struct nlist symbol; /* symbol table entry */
char *ptr,ttext[1024],symbolname[80],symboltype[80];
char params[1024],tempstring[1024],outtext[80];
int ii;
char cc;
short ss;
long ll,l2;
unsigned char uc;
unsigned short us;
unsigned long ul;
unsigned int ui;
float ff;
double dd;
long vv;
/*------------------------------------*/
strcpy(params,level[ilevel].funcname);
strcat(params,"(");
isym= level[ilevel].funcsymbol+1;
nseek= exe.symoffset + isym*sizeof(symbol);
/* do a quick loop to get parameter names */
fseek(fp,nseek,0);
for(i=isym;i<exe.nsym;i++)
{status= fread(&symbol,sizeof(symbol),1,fp);
if(status==0) printf("could not read symbol\n");
type= symbol.n_type;
if(type==N_FUN) break; /* that is all for this function */
else if(type==N_SO) break; /* that is all for this function */
else if(type==N_PSYM) /* parameter: name,,0,type,offset */
{addr= symbol.n_un.n_strx; /* symbol name in string table */
fseek(fp2,exe.stroffset,0);
fseek(fp2,addr,1);
ptr= fgets(ttext,sizeof(ttext),fp2);
/* extract the symbol's name */
strcpy(tempstring,ttext);
str_whiteout(tempstring,":=;");
sscanf(tempstring,"%s",symbolname);
strcat(params,symbolname); strcat(params,",");
}
}
/* change the last comma to an ) and print the parameters */
ll= strlen(params);
if(params[ll-1]==',') params[ll-1]= ')'; else strcat(params,")");
fprintf(fpcrash,"%s\n",params);
/* do a second loop to get values */
fseek(fp,nseek,0);
for(i=isym;i<exe.nsym;i++)
{status= fread(&symbol,sizeof(symbol),1,fp);
if(status==0) printf("could not read symbol\n");
type= symbol.n_type;
if(type==N_FUN) break; /* that is all for this function */
else if(type==N_SO) break; /* that is all for this function */
else if(type!=N_PSYM)continue;
addr= symbol.n_un.n_strx;
off= symbol.n_value; /* offset from stack frame end */
fseek(fp2,exe.stroffset,0);
fseek(fp2,addr,1);
ptr= fgets(ttext,sizeof(ttext),fp2);
/* extract the symbol's name */
strcpy(tempstring,ttext);
str_whiteout(tempstring,":=;");
sscanf(tempstring,"%s",symbolname);
/* extract text we use to get the symbol's type */
ptr= strchr(ttext,':');
strcpy(symboltype,ptr);
stackbase= level[ilevel].frameend;
address= stackbase+off; /* where the variable's bytes are */
/* find out what kind of symbol it is */
trb_translate(ttext,&code,&pointer,&array);
#if PARAMDUMP
printf("param: >%s< off=%d\n",ttext,off);
trb_verbalize(symbolname,code,pointer,array);
#endif
/* if it is a pointer, print the address & dereference it */
if(pointer==1)
{newaddress= *(unsigned long *) address;
fprintf(fpcrash," %s = 0x%x (pointer to %s) \n",
symbolname, newaddress, description[code]);
if(newaddress>=0 && newaddress<0x1000) continue;
else address= newaddress;
}
else if(pointer==2) /* it could be a pointer to a pointer */
{newaddress= *(unsigned long *) address;
fprintf(fpcrash," %s = 0x%x (pointer to *%s) \n",
symbolname, newaddress, description[code]);
if(newaddress>=0 && newaddress<0x1000) continue;
else address= newaddress;
newaddress= *(unsigned long *) address;
if(newaddress>=0 && newaddress<0x1000) continue;
else address= newaddress;
}
/* treat a ptr to char as an array */
if(pointer>0 && code==D_CHAR) goto arrays; /* written by an ex- */
/* fortran programmer */
/* an array of any type */
if(array>1) goto arrays;
/* int */
else if(code==D_INT)
{ii= *(int *)address;
sprintf(outtext,"%d 0x%x (long)",ii,ii);}
/* char */
else if(code==D_CHAR)
{cc= *(char *)address;
sprintf(outtext,"\'%c\' 0x%x (char)",cc,cc);}
/* long */
else if(code==D_LONG)
{ll= *(long *)address;
sprintf(outtext,"%d 0x%x (long)",ll,ll);}
/* short */
else if(code==D_SHORT)
{ss= *(short *)address;
sprintf(outtext,"%hd 0x%hx (short)",ss,ss);}
/* unsigned char */
else if(code==D_UCHAR)
{uc= *(unsigned char *)address;
sprintf(outtext,"\'%c\' 0x%x (u char)",uc,uc);}
/* unsigned short */
else if(code==D_USHORT)
{us= *(unsigned short *)address;
sprintf(outtext,"%hd 0x%hx (u short)",us,us);}
/* unsigned long */
else if(code==D_ULONG)
{ul= *(unsigned long *)address;
sprintf(outtext,"%u 0x%x (u long)",ul,ul);}
/* unsigned int */
else if(code==D_UINT)
{ui= *(unsigned int *)address;
sprintf(outtext,"%u 0x%x (u int)",ui,ui);}
/* float */
else if(code==D_FLOAT)
{ff= *(float *)address;
ll= *(long *)address;
sprintf(outtext,"%f 0x%08x (float)",ff,ll);}
/* double */
else if(code==D_DOUBLE)
{dd= *(double *)address;
ll= *(long *)address;
l2= *(long *)(address+sizeof(long));
sprintf(outtext,"%f 0x%08x%08x (double)",dd,ll,l2);}
/* void */
else if(code==D_VOID)
{vv= *(long *)address;
sprintf(outtext,"%d 0x%x (void)",vv,vv);}
/* ??? */
else
sprintf(outtext," unknown type ");
if(pointer==0)fprintf(fpcrash," %s = %s \n",symbolname,outtext);
else if(pointer==1)fprintf(fpcrash," *%s = %s \n",symbolname,outtext);
else if(pointer==2)fprintf(fpcrash," **%s = %s \n",symbolname,outtext);
continue;
/*---------*/
arrays:
/*---------*/
size= array-1;
middle= array/2;
/* int or long array */
if(code==D_INT || code==D_LONG)
{fprintf(fpcrash," %s = an array of type %s \n",
symbolname,description[code]);
ii= *(int *)address;
fprintf(fpcrash," %s[0] = %d 0x%x \n", symbolname,ii,ii);
ii= *(int *) (address+middle*sizeof(int));
fprintf(fpcrash," %s[%d] = %d 0x%x \n", symbolname,middle,ii,ii);
ii= *(int *) (address+size*sizeof(int));
fprintf(fpcrash," %s[%d] = %d 0x%x \n", symbolname,size,ii,ii);
}
/* char array */
else if(code==D_CHAR)
{sum=pointer;
if(array>1)sum++;
else if(sum==1)
fprintf(fpcrash," *%s = \"%s\"\n",symbolname,address);
else if(sum==2)
fprintf(fpcrash," *%s = \"%s\"\n",symbolname,address);
}
/* float array */
else if(code==D_FLOAT)
{fprintf(fpcrash," %s = an array of type %s \n",
symbolname,description[code]);
ff= *(float *)address;
fprintf(fpcrash," %s[0] = %f 0x%x \n", symbolname,ff,ff);
ff= *(float *) (address+middle*sizeof(float));
fprintf(fpcrash," %s[%d] = %f 0x%x \n", symbolname,middle,ff,ff);
ff= *(float *) (address+size*sizeof(float));
fprintf(fpcrash," %s[%d] = %f 0x%x \n", symbolname,size,ff,ff);
}
/* need to put in other types of arrays */
} /* end of loop over all nsym */
} /* end of trb_params */
/****************************************************************/
/* trb_symbols */
/* print local symbols in procedure of interest */
/****************************************************************/
static void trb_symbols(ilevel,fp,fp2)
int ilevel;
FILE *fp, *fp2;
{
int i,type,status,isym;
int code,pointer,array,middle,size;
long addr,off,address,newaddress,stackbase;
unsigned long value;
long nseek;
struct nlist symbol; /* symbol table entry */
char *ptr,ttext[1024],tempstring[1024];
char symbolname[80],symboltype[80];
short int jtemp; unsigned short jtemp2;
char outtext[80];
int ii;
char cc;
short ss;
long ll,l2;
unsigned char uc;
unsigned short us;
unsigned long ul;
unsigned int ui;
float ff;
double dd;
long vv;
/*-----------------------------------*/
isym= level[ilevel].funcsymbol+1;
nseek= exe.symoffset + isym*sizeof(symbol);
fseek(fp,nseek,0);
stackbase= level[ilevel].frameend;
for(i=isym;i<exe.nsym;i++)
{status= fread(&symbol,sizeof(symbol),1,fp);
if(status==0) printf("could not read symbol\n");
type= symbol.n_type;
if(type==N_FUN) return; /* new function */
else if(type==N_SO) return; /* new source file */
else if(type!=N_LSYM) continue; /* local sym: name,,0,type,offset */
addr= symbol.n_un.n_strx; /* pointer to string table */
off= symbol.n_value; /* offset from stack frame end */
fseek(fp2,exe.stroffset,0);
fseek(fp2,addr,1);
ptr= fgets(ttext,sizeof(ttext),fp2);
/* get the symbol's name */
strcpy(tempstring,ttext);
str_whiteout(tempstring,":=;");
sscanf(tempstring,"%s",symbolname);
/* get text used to find type of symbol */
ptr= strchr(ttext,':');
strcpy(symboltype,ptr);
address= stackbase+off;
/* find out what kind of symbol it is */
trb_translate(ttext,&code,&pointer,&array);
#if SYMBOLDUMP
printf("symbol: >%s< off=%d\n",ttext,off);
trb_verbalize(symbolname,code,pointer,array);
#endif
/* if it is a pointer, print the address & dereference it */
if(pointer==1)
{newaddress= *(unsigned long *) address;
fprintf(fpcrash," %s = 0x%x (pointer to %s) \n",
symbolname, newaddress, description[code]);
if(newaddress>=0 && newaddress<0x1000) continue;
else address= newaddress;
}
else if(pointer==2) /* could have pointer to pointer */
{newaddress= *(unsigned long *) address;
fprintf(fpcrash," %s = 0x%x (pointer to *%s) \n",
symbolname, newaddress, description[code]);
if(newaddress>=0 && newaddress<0x1000) continue;
else address= newaddress;
newaddress= *(unsigned long *) address;
if(newaddress>=0 && newaddress<0x1000) continue;
else address= newaddress;
}
/* treat a ptr to char as an array */
if(pointer>0 && code==D_CHAR) goto arrays;
/* an array of any type */
if(array>1) goto arrays;
/* int */
else if(code==D_INT)
{ii= *(int *)address;
sprintf(outtext,"%d 0x%x (long)",ii,ii);}
/* char */
else if(code==D_CHAR)
{cc= *(char *)address;
sprintf(outtext,"\'%c\' 0x%x (char)",cc,cc);}
/* long */
else if(code==D_LONG)
{ll= *(long *)address;
sprintf(outtext,"%f 0x%x (long)",ll,ll);}
/* short */
else if(code==D_SHORT)
{ss= *(short *)address;
sprintf(outtext,"%hd 0x%hx (short)",ss,ss);}
/* unsigned char */
else if(code==D_UCHAR)
{uc= *(unsigned char *)address;
sprintf(outtext,"\'%c\' 0x%x (u char)",uc,uc);}
/* unsigned short */
else if(code==D_USHORT)
{us= *(unsigned short *)address;
sprintf(outtext,"%hd 0x%hx (u short)",us,us);}
/* unsigned long */
else if(code==D_ULONG)
{ul= *(unsigned long *)address;
sprintf(outtext,"%u 0x%x (u long)",ul,ul);}
/* unsigned int */
else if(code==D_UINT)
{ui= *(unsigned int *)address;
sprintf(outtext,"%u 0x%x (u int)",ui,ui);}
/* float */
else if(code==D_FLOAT)
{ff= *(float *)address;
ll= *(long *)address;
sprintf(outtext,"%f 0x%08x (float)",ff,ll);}
/* double */
else if(code==D_DOUBLE)
{dd= *(double *)address;
ll= *(long *)address;
l2= *(long *)(address+sizeof(long));
sprintf(outtext,"%f 0x%08x%08x (double)",dd,ll,l2);}
/* void */
else if(code==D_VOID)
{vv= *(long *)address;
sprintf(outtext,"%d 0x%x (void)",vv,vv);}
/* ??? */
else
sprintf(outtext," unknown type ");
if(pointer==0)fprintf(fpcrash," %s = %s \n",symbolname,outtext);
else if(pointer==1)fprintf(fpcrash," *%s = %s \n",symbolname,outtext);
continue;
/*---------*/
arrays:
/*---------*/
size= array-1;
middle= array/2;
/* int or long array */
if(code==D_INT || code==D_LONG)
{fprintf(fpcrash," %s = an array of type %s \n",
symbolname,description[code]);
ii= *(int *)address;
fprintf(fpcrash," %s[0] = %d 0x%x \n", symbolname,ii,ii);
ii= *(int *) (address+middle*sizeof(int));
fprintf(fpcrash," %s[%d] = %d 0x%x \n", symbolname,middle,ii,ii);
ii= *(int *) (address+size*sizeof(int));
fprintf(fpcrash," %s[%d] = %d 0x%x \n", symbolname,size,ii,ii);
}
/* char array */
else if(code==D_CHAR)
fprintf(fpcrash," %s = \"%s\" \n",symbolname,address);
/* float array */
else if(code==D_FLOAT)
{fprintf(fpcrash," %s = an array of type %s \n",
symbolname,description[code]);
ff= *(float *)address;
ll= *(long *)address;
fprintf(fpcrash," %s[0] = %f 0x%x \n", symbolname,ff,ll);
ff= *(float *) (address+middle*sizeof(float));
ll= *(long *) (address+middle*sizeof(float));
fprintf(fpcrash," %s[%d] = %f 0x%x \n", symbolname,middle,ff,ll);
ff= *(float *) (address+size*sizeof(float));
ll= *(long *) (address+size*sizeof(float));
fprintf(fpcrash," %s[%d] = %f 0x%x \n", symbolname,size,ff,ll);
}
/* dump other kinds of arrays */
} /* end of loop over all nsym */
} /* end of trb_symbols */
/****************************************************************/
/* trb_traceback */
/* print a traceback */
/****************************************************************/
static void trb_traceback(nlevel)
int nlevel;
{
int i;
FILE *fp,*fp2;
/*---------------------------*/
if(nlevel<1)return;
/* use first file pointer to read the symbol table */
fp= fopen(exe.name,"r");
if(fp==NULL) {printf("can't open %s\n",exe.name);exit(1);}
/* use second file pointer to read the string table */
fp2= fopen(exe.name,"r");
/* print a traceback to the screen */
fprintf(fpcrash,"---------- traceback ----------\n");
for(i=0;i<nlevel;i++)
if(level[i].found!=0)fprintf(fpcrash,"file %s line %d function %s() \n",
level[i].filename, level[i].line, level[i].funcname);
else
fprintf(fpcrash,"address %x \n", level[i].programcounter);
for(i=0;i<nlevel;i++)
{
fprintf(fpcrash,"------------------------------------\n");
if(level[i].found!=0)
{
trb_dictionary(i,fp,fp2);
trb_params(i,fp,fp2);
fprintf(fpcrash," -- local symbols for %s --\n",level[i].funcname);
trb_symbols(i,fp,fp2);
}
}
fclose(fp2);
fclose(fp);
} /* end of trb_traceback */
/****************************************************************/
/* trb_userinfo */
/* put program name, user, etc into a file */
/****************************************************************/
void trb_userinfo(fp)
FILE *fp;
{
int ll;
char *user,host[64],nouser[8];
time_t timeofday;
char fulltime[26];
/* get the user's name */
user= (char *) getlogin();
if(user==NULL)user= (char *)getpwuid(getuid());
if(user==NULL){strcpy(nouser,"????"); user=nouser; }
/* get the time */
timeofday=time((time_t *)0);
strcpy(fulltime,ctime(&timeofday));
fulltime[24]=CNULL;
/* get the host */
gethostname(host,64);
/* write to a file */
fprintf(fp,"user=%s host=%s date=%s \n", user,host,fulltime);
fprintf(fp,"program=%s \n", exe.name);
} /* end of trb_userinfo */
/****************************************************************/
/* trb_handle */
/* handle all signals */
/****************************************************************/
void trb_handle(sig,code,scp,addr)
int sig, code;
struct sigcontext *scp;
char *addr;
{
int i,j,exitflag;
int nlevel;
unsigned long programcounter,stackpointer,frameend;
unsigned long instruction;
char *ptr;
char *startdump;
/*--------------------*/
/* write to a file called CRASH */
if(fpcrash==0) fpcrash= fopen("CRASH","a"); /* open for append */
if(fpcrash==NULL) fpcrash= stdout; /* if failure, use standard output */
fprintf(fpcrash,"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
trb_userinfo(fpcrash);
/* print meaningful message for signal */
fprintf(fpcrash,"%s signal=%d(%d) \n",sigtext[sig],sig,code);
ptr= trb_codetext(sig,code);
if(ptr!=NULL) fprintf(fpcrash,"%s\n",ptr);
if( (long)addr > 0x1000) /* had a value 0f 0x2 once */
{instruction= *(long *) addr;
fprintf(fpcrash,"instruction is %X \n",instruction);
}
/* get stack pointer & program counter */
programcounter= scp->sc_pc;
stackpointer= scp->sc_sp;
frameend= *( (long *)stackpointer +JUMPSP);
DBPRINT((" pc=0x%x sp=0x%x \n", programcounter,stackpointer));
#if STACKDUMP
startdump= (char *)scp->sc_sp;
startdump= startdump-16;
trb_stackdump(startdump,DUMPSIZE,&fpstackdump);
#endif
/* walk the stack, storing stack pointers & program counters */
nlevel= 0;
while(stackpointer!=0)
{level[nlevel].programcounter= programcounter;
level[nlevel].frameend= frameend;
level[nlevel].stackpointer= stackpointer;
if(nlevel<MAXLEVEL)nlevel++;
DBPRINT(("sp=%08x pc=%08x\n",stackpointer,programcounter));
#if FRAMEDUMP
trb_framedump(stackpointer,programcounter,frameend,&fpframedump);
#endif
programcounter= *( (long *)stackpointer +JUMPPC);
stackpointer= *( (long *)stackpointer +JUMPSP);
if(stackpointer!=0) frameend= *( (long *)stackpointer +JUMPSP);
if(frameend==0) stackpointer= 0; /* we are at the end */
}
trb_exeinfo(); /* get info from file header */
trb_getline(nlevel); /* convert addresses to line numbers */
trb_traceback(nlevel); /* print a full traceback */
#if SYMBOLDUMP
trb_symboldump();
#endif
exitflag= 0;
switch(sig)
{case SIGTRAP: exitflag= 1; break;
case SIGSEGV: exitflag= 1; break;
case SIGABRT: exitflag= 1; break;
case SIGBUS: exitflag= 1; break;
case SIGILL: exitflag= 1; break;
case SIGFPE:
switch(code)
{case FPE_INTOVF_TRAP: exitflag= 1; break;
case FPE_STARTSIG_TRAP: exitflag= 1; break;
case FPE_INTDIV_TRAP: exitflag= 1; break;
case FPE_FLTINEX_TRAP: exitflag= 1; break;
case FPE_FLTDIV_TRAP: exitflag= 1; break;
case FPE_FLTUND_TRAP: exitflag= 1; break;
case FPE_FLTOPERR_TRAP: exitflag= 1; break;
case FPE_FLTOVF_TRAP: exitflag= 1; break;
default: break;
}
break; /* end of SIGFPE */
default:
printf("signal %d sent to trb_handle \n",sig);
break;
} /* end of switch on sig */
fprintf(fpcrash,"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
#if FRAMEDUMP
fclose(fpframedump);
#endif
if(exitflag)
{if(fpcrash!=stdout) {fclose(fpcrash); system("ls -l CRASH");}
exit(sig);
}
return;
} /* end of trb_handle */
/****************************************************************/
/* trb_sigtextinit */
/* initialize signal text messages */
/****************************************************************/
static void trb_sigtextinit()
{
strcpy(sigtext[1], "SIGHUP: hangup signal received");
strcpy(sigtext[2], "SIGINT: interrupt signal received");
strcpy(sigtext[3], "SIGQUIT: quit signal received");
strcpy(sigtext[4], "SIGILL: illegal instruction (not reset when caught)");
strcpy(sigtext[5], "SIGTRAP: trace trap (not reset when caught)");
strcpy(sigtext[6], "SIGABRT: abort or IOT instruction");
strcpy(sigtext[7], "SIGEMT: EMT instruction");
strcpy(sigtext[8], "SIGFPE: floating point exception");
strcpy(sigtext[9], "SIGKILL: kill signal received");
strcpy(sigtext[10], "SIGBUS: bus error");
strcpy(sigtext[11], "SIGSEGV: segmentation violation");
strcpy(sigtext[12], "SIGSYS: bad argument to system call");
strcpy(sigtext[13], "SIGPIPE: write on a pipe with no one to read it");
strcpy(sigtext[14], "SIGALRM: alarm clock signal received");
strcpy(sigtext[15], "SIGTERM: received software termination signal");
strcpy(sigtext[16], "SIGURG: urgent condition on IO channel");
strcpy(sigtext[17], "SIGSTOP: sendable stop signal not from tty");
strcpy(sigtext[18], "SIGTSTP: received stop signal from tty");
strcpy(sigtext[19], "SIGCONT: continue a stopped process");
strcpy(sigtext[20], "SIGCHLD: child process has stopped or exited");
strcpy(sigtext[21], "SIGTTIN: to readers pgrp upon background tty read");
strcpy(sigtext[22], "SIGTTOU: like TTIN for output if (tp->t_local<OSTOP)");
strcpy(sigtext[23], "SIGIO: input/output possible signal");
strcpy(sigtext[24], "SIGXCPU: exceeded CPU time limit");
strcpy(sigtext[25], "SIGXFSZ: exceeded file size limit");
strcpy(sigtext[26], "SIGVTALRM: received virtual time alarm");
strcpy(sigtext[27], "SIGPROF: received profiling time alarm");
strcpy(sigtext[28], "SIGWINCH: window changed");
strcpy(sigtext[29], "SIGLOST: resource lost (eg, record-lock lost)");
strcpy(sigtext[30], "SIGUSR1: received user defined signal 1");
strcpy(sigtext[31], "SIGUSR2: received user defined signal 2");
} /* end if trb_sigtextinit */
/****************************************************************/
/* trb_codetext */
/* return text explanation of signal */
/****************************************************************/
static char *trb_codetext(sig,code)
int sig,code;
{
if(sig==SIGILL)
{if(code==ILL_STACK) return("bad stack");
else if(code==ILL_ILLINSTR_FAULT) return("illegal instruction fault");
else if(code==ILL_PRIVINSTR_FAULT) return("privileged instruction fault");
else if(code>=0x80 & code<=0xff) return("software trap");
else return(NULL);
}
else if(sig==SIGFPE)
{if(code==FPE_INTOVF_TRAP) return("integer overflow");
else if(code==FPE_STARTSIG_TRAP) return("process using fp");
else if(code==FPE_INTDIV_TRAP) return("integer divide by zero");
else if(code==FPE_FLTINEX_TRAP) return("floating inexact result");
else if(code==FPE_FLTDIV_TRAP) return("floating divide by zero");
else if(code==FPE_FLTUND_TRAP) return("floating underflow");
else if(code==FPE_FLTOPERR_TRAP) return("floating operand error");
else if(code==FPE_FLTOVF_TRAP) return("floating overflow");
else return(NULL);
}
else if(sig==SIGBUS)
{if(code==BUS_HWERR) return("misc hardware error (e.g. timeout)");
else if(code==BUS_ALIGN) return("hardware alignment error");
else if(code==BUS_OBJERR) return("object returned errno value");
else return(NULL);
}
else if(sig==SIGSEGV)
{if(code==SEGV_NOMAP) return("no mapping at the fault address");
else if(code==SEGV_PROT) return("access exceeded protections");
else if(code==SEGV_OBJERR) return("object returned errno value");
else return(NULL);
}
else
return(NULL);
} /* end of trb_codetext */
/****************************************************************/
/* trb_signal */
/* initiate trapping of all signals */
/****************************************************************/
static void trb_signal()
{
int status;
sigfpe_handler_type funcname;
/*---------------------------------------*/
trb_sigtextinit();
/* trap the important signals */
/* signal(SIGILL,trb_handle);
signal(SIGTRAP,trb_handle); */
signal(SIGFPE,trb_handle); /* floating point errors */
signal(SIGBUS,trb_handle); /* bus errors */
signal(SIGSEGV,trb_handle); /* segmentation faults */
signal(SIGABRT,trb_handle); /* to get integer divide */
/* don't trap the rest */
#if 0
signal(SIGHUP,trb_handle);
signal(SIGINT,trb_handle);
signal(SIGQUIT,trb_handle);
signal(SIGEMT,trb_handle);
signal(SIGKILL,trb_handle);
signal(SIGSYS,trb_handle);
signal(SIGPIPE,trb_handle);
signal(SIGALRM,trb_handle);
signal(SIGTERM,trb_handle);
signal(SIGURG,trb_handle);
signal(SIGSTOP,trb_handle);
signal(SIGTSTP,trb_handle);
signal(SIGCONT,trb_handle);
signal(SIGCHLD,trb_handle);
signal(SIGTTIN,trb_handle);
signal(SIGTTOU,trb_handle);
signal(SIGIO,trb_handle);
signal(SIGXCPU,trb_handle);
signal(SIGXFSZ,trb_handle);
signal(SIGVTALRM,trb_handle);
signal(SIGPROF,trb_handle);
signal(SIGWINCH,trb_handle);
signal(SIGLOST,trb_handle);
signal(SIGUSR1,trb_handle);
signal(SIGUSR2,trb_handle);
#endif
/* invoke special ieee handler to catch integer divide by zero */
funcname= (sigfpe_handler_type)trb_handle;
status= ieee_handler("set","all",funcname);
if(status!=0)printf("can't set ieee all\n");
/* ignore inexact representation of float point numbers */
status= ieee_handler("clear","inexact",funcname);
if(status!=0)printf("can't clear ieee inexact\n");
} /* end of trb_signal */
/****************************************************************/
/* trb_signalinit */
/* initiate trapping of all signals */
/****************************************************************/
void trb_signalinit(argc,argv)
int argc;
char *argv[];
{
FILE *fp;
/*---------------------------------------*/
/* find the executable file */
trb_exefind(argc,argv);
/* remove files CRASH, STACKDUMP, & FRAMEDUMP */
fp= fopen("CRASH","w");
if(fp!=NULL) fclose(fp);
fp= fopen("STACKDUMP","w");
if(fp!=NULL) fclose(fp);
fp= fopen("FRAMEDUMP","w");
if(fp!=NULL) fclose(fp);
fpcrash= 0;
fpstackdump= 0;
fpframedump= 0;
/* set up our signal handler */
trb_signal();
} /* end of ita_signalinit */
/*****************************************************************/
/* strstr */
/* returns a pointer to first occurence of a substring */
/*****************************************************************/
static char *strstr(string,phrase)
char *string,*phrase;
{
char *ptr1, *ptr2;
/*------------------------------------------------------*/
if(strlen(string)==0) return(NULL);
if(strlen(phrase)==0) return(NULL);
for (; (string= strchr(string, *phrase)) !=NULL; ++string)
{for (ptr1= string, ptr2= phrase; ;)
if(*++ptr2 == CNULL) return (string);
else if (*++ptr1 != *ptr2)break;
}
return (NULL);
}
/**************************************************************/
/* str_getdelimited */
/* returns substring bounded by 2 characters */
/**************************************************************/
static void str_getdelimited(intext,bounds,outtext)
char *intext,*bounds,*outtext;
{
int ll;
char start, end;
char *ptr, *ptr2;
/*------------------------------------------------------*/
outtext[0]=CNULL;
start= bounds[0];
end= bounds[1];
ptr=strchr(intext,start);
if(ptr==NULL)return;
ptr++;
ptr2=strchr(ptr,end);
if(ptr2==NULL)return;
ll=ptr2-ptr;
strncpy(outtext,ptr,ll);
outtext[ll]=CNULL;
}
/********************************************************/
/* str_whiteout */
/* routine to change certain characters to blanks */
/********************************************************/
static void str_whiteout(string,chars)
char *string,*chars;
{
/*... locals */
int i,j,ls,lc;
char cc;
/*-----------------------------*/
ls=strlen(string);
if(ls<1)return;
lc=strlen(chars);
if(lc<1)return;
for(i=0;i<ls;i++)
{cc=string[i];
for(j=0;j<lc;j++)if(cc==chars[j])cc=' ';
string[i]=cc;
}
} /* end of str_whiteout */